package com.catazy.album.data.datasource.database.model

import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import com.catazy.album.domain.model.Album
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

/**
 * 作者: Tao
 * 日期: 2024/12/23
 * 时间: 10:36
 * 描述: AlbumEntity数据库
 */

// 标记一个数据类为数据库中的一个表
@Entity(tableName = "albums")
// 此注解用于指定类型转换器（Type Converters），这些转换器用于将数据库中不支持的数据类型（如 List、Date 等）转换为支持的类型（如 String），以及反向转换。
// 需要在数据库中存储复杂数据类型时，使用类型转换器来处理这些类型的序列化和反序列化
@TypeConverters(
    AlbumImageEntityTypeConverter::class,
    AlbumTrackEntityTypeConverter::class,
    AlbumTagEntityTypeConverter::class,
)
internal data class AlbumEntityModel(
    // 主键，自动生成
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    // 音乐脑数据库ID
    val mbId: String,
    // 专辑名称
    val name: String,
    // 艺术家名称
    val artist: String,
    // 专辑图片列表，默认为空列表
    val images: List<ImageEntityModel> = listOf(),
    // 专辑曲目列表，可能为空
    val tracks: List<TrackEntityModel>?,
    // 专辑标签列表，可能为空
    val tags: List<TagEntityModel>?,
)

/**
 * 将实体模型转换为领域模型
 * 此函数将AlbumEntityModel实例转换为Album领域模型，包括将相关联的图片、曲目和标签实体模型转换为相应的领域模型。
 *
 * @return 转换后的Album领域模型实例
 */
internal fun AlbumEntityModel.toDomainModel() =
    Album(
        this.name,
        this.artist,
        this.mbId,
        this.images.mapNotNull { it.toDomainModel() },
        this.tracks?.map { it.toDomainModel() },
        this.tags?.map { it.toDomainModel() },
    )

/**
 * 类[AlbumImageEntityTypeConverter]用于在数据库中[ImageEntityModel]列表与JSON字符串之间的相互转换。
 * 这在持久化数据到数据库或从数据库读取数据时非常有用，尤其是在使用Room数据库时，
 * 可以通过类型转换器将对象列表与字符串进行互换。
 */
internal class AlbumImageEntityTypeConverter {

    /**
     * 将JSON字符串转换为[ImageEntityModel]对象列表的函数。
     * 这个函数主要用于从数据库读取数据时，将存储的JSON字符串解析回对象列表。
     *
     * @param data 可能为空的JSON字符串，代表一个[ImageEntityModel]列表。
     * @return 解析后的[ImageEntityModel]列表。如果输入为空，则返回空列表。
     */
    @TypeConverter
    fun stringToList(data: String?) =
        data?.let { Json.decodeFromString<List<ImageEntityModel>>(it) } ?: listOf()

    /**
     * 将[ImageEntityModel]对象列表转换为JSON字符串的函数。
     * 这个函数主要用于将数据持久化到数据库时，将对象列表转换为可存储的字符串格式。
     *
     * @param someObjects [ImageEntityModel]的列表，将被转换为JSON字符串。
     * @return 代表输入列表的JSON字符串。
     */
    @TypeConverter
    fun listToString(someObjects: List<ImageEntityModel>): String = Json.encodeToString(someObjects)
}

/**
 * 类[AlbumTrackEntityTypeConverter]用于在数据库中[TrackEntityModel]列表与JSON字符串之间的相互转换。
 */
internal class AlbumTrackEntityTypeConverter {

    /**
     * 将JSON字符串转换为[TrackEntityModel]对象列表的函数。
     * 这个函数主要用于从数据库读取数据时，将存储的JSON字符串解析回对象列表。
     *
     * @param data 可能为空的JSON字符串，代表一个[TrackEntityModel]列表。
     * @return 解析后的[TrackEntityModel]列表。如果输入为空，则返回空列表。
     */
    @TypeConverter
    fun stringToList(data: String?) =
        data?.let { Json.decodeFromString<List<TrackEntityModel>>(it) } ?: listOf()

    /**
     * 将[TrackEntityModel]对象列表转换为JSON字符串的函数。
     * 这个函数主要用于将数据持久化到数据库时，将对象列表转换为可存储的字符串格式。
     *
     * @param someObjects [TrackEntityModel]的列表，将被转换为JSON字符串。
     * @return 代表输入列表的JSON字符串。
     */
    @TypeConverter
    fun listToString(someObjects: List<TrackEntityModel>): String =
        Json.encodeToString(someObjects)
}

/**
 * 类[AlbumTagEntityTypeConverter]用于在数据库中[TagEntityModel]列表与JSON字符串之间的相互转换。
 */
internal class AlbumTagEntityTypeConverter {

    /**
     * 将JSON字符串转换为[TagEntityModel]对象列表的函数。
     * 这个函数主要用于从数据库读取数据时，将存储的JSON字符串解析回对象列表。
     *
     * @param data 可能为空的JSON字符串，代表一个[TagEntityModel]列表。
     * @return 解析后的[TagEntityModel]列表。如果输入为空，则返回空列表。
     */
    @TypeConverter
    fun stringToList(data: String?) =
        data?.let { Json.decodeFromString<List<TagEntityModel>>(it) } ?: listOf()

    /**
     * 将[TagEntityModel]对象列表转换为JSON字符串的函数。
     * 这个函数主要用于将数据持久化到数据库时，将对象列表转换为可存储的字符串格式。
     *
     * @param someObjects [TagEntityModel]的列表，将被转换为JSON字符串。
     * @return 代表输入列表的JSON字符串。
     */
    @TypeConverter
    fun listToString(someObjects: List<TagEntityModel>): String =
        Json.encodeToString(someObjects)
}
